package device_map

import (
	"path"
	"strconv"

	"device-admin/config"
	"device-admin/config/mysql"
	"device-admin/internal/app/grpc/protoc/robotc"
	"device-admin/internal/define"
	"device-admin/internal/models"
	"device-admin/internal/pkg/file"

	"192.168.1.75/go-pkg/errorx"
	"192.168.1.75/go-pkg/helper"
	"github.com/shopspring/decimal"
	"google.golang.org/protobuf/proto"
	"gorm.io/gorm"
)

// GetLatestMap 获取最近使用的地图
func GetLatestMap(robotID string) (mapName, mapImg, mapExt string, err error) {
	var device models.Device
	// 参数检查
	if robotID == "" {
		return "", "", "", errorx.New("设备id不能为空", -1)
	}

	db := mysql.NewDB()
	// 当前设备正在使用的地图名称
	rowsAffected := db.Model(&models.Device{}).
		Where(&models.Device{RobotID: robotID}).
		Take(&device).RowsAffected
	if rowsAffected <= 0 {
		return "", "", "", errorx.New("设备不存在", -1)
	}
	// 当前设备正在使用的地图路径及扩展数据
	var record models.DeviceMap
	db.Model(&models.DeviceMap{}).
		Select("map_md5", "map_ex_md5").
		Where("robot_id = ?", robotID).
		Where("map_name = ?", device.CurrentMapName).
		Where("deleted_at = ?", 0).
		Take(&record)

	return device.CurrentMapName,
		"/" + path.Join("file", "device-admin", "device-map", record.RobotID, record.MapMd5+".png"),
		"/" + path.Join("file", "device-admin", "device-map", record.RobotID, record.MapExMd5+".ext"),
		nil
}

// MapList 地图列表
func MapList(robotID string, mapName string, page, limit int) (interface{}, int64, error) {
	// 参数检查
	if robotID == "" {
		return []string{}, 0, errorx.New("设备id不能为空", -1)
	}

	// 获取设备信息
	var device models.Device
	mysql.NewDB().Model(&models.Device{}).Where(&models.Device{RobotID: robotID}).Take(&device)

	// 共享参数
	tx := mysql.NewDB().Model(&models.DeviceMap{}).
		Where("robot_id = ?", robotID).
		Where("deleted_at = ?", 0)

	if mapName != "" {
		tx = tx.Where("map_name = ?", mapName)
	}
	tx = tx.Session(&gorm.Session{})

	// 获取总条数
	var total int64
	tx.Count(&total)

	// 获取数据
	// 要判断正在使用的图片
	// 可以从设备上报的实时数据获取正在使用的地图
	var list []struct {
		models.DeviceMap
		MapImage string `json:"map_image" gorm:"-"`
		InUse    int    `json:"in_use" gorm:"-"`
	}
	helper.Gorm{}.Paginate(tx, page, limit).
		Select(
			"id",
			"robot_id",
			"map_md5",
			"map_name",
			"map_ex_md5",
			"height",
			"width",
			"created_at",
			"updated_at",
		).
		Order("used_at desc").
		Find(&list)

	// 记录处理
	for index, record := range list {
		// 地图图片地址
		list[index].MapImage = "/" + path.Join("file", "device-admin", "device-map", record.RobotID, record.MapMd5+".png")
		// 地图宽和高保留两位小数
		list[index].Width, _ = decimal.NewFromFloat(record.Width).Truncate(2).Float64()
		list[index].Height, _ = decimal.NewFromFloat(record.Height).Truncate(2).Float64()
		// 是否正在使用
		if record.MapName == device.CurrentMapName {
			list[index].InUse = 1
		}
	}

	return list, total, nil
}

// TaskList 地图列表
func TaskList(robotID string, mapName string) (interface{}, error) {
	type taskSt struct {
		Name           string `json:"name"`
		PathName       string `json:"path_name"`
		StartTime      string `json:"start_time"`
		EndTime        string `json:"end_time"`
		RunCount       int    `json:"run_count"`
		TaskStatus     int    `json:"task_status"`
		TaskStatusName string `json:"task_status_name"`
	}
	var (
		deviceMap models.DeviceMap
		taskList  []taskSt
	)
	total := mysql.NewDB().Model(&models.DeviceMap{}).
		Where("robot_id = ?", robotID).
		Where("map_name = ?", mapName).
		Where("deleted_at = ?", 0).
		Take(&deviceMap).
		RowsAffected

	if total == 0 {
		return []string{}, errorx.New("地图不存在", -1)
	}
	mapEx := &robotc.ReqDDRVLNMapEx{}
	mapExtData, err1 := file.ReadMapFile(config.Config.FileSaveDir, path.Join(deviceMap.RobotID, deviceMap.MapExMd5)+".ext")
	err2 := proto.Unmarshal(mapExtData, mapEx)
	if err1 != nil || err2 != nil || len(mapExtData) == 0 {
		return []string{}, errorx.New("正在同步地图，请稍后！", -1)
	}

	taskItems := mapEx.GetTaskSet()
	for _, taskItem := range taskItems {
		startHour := strconv.Itoa(int(taskItem.GetTimeSet().GetStartHour()))
		startMin := strconv.Itoa(int(taskItem.GetTimeSet().GetStartMin()))
		endHour := strconv.Itoa(int(taskItem.GetTimeSet().GetEndHour()))
		endMin := strconv.Itoa(int(taskItem.GetTimeSet().GetEndMin()))
		pathName := ""
		if len(taskItem.GetPathSet()) > 0 {
			pathName = string(taskItem.GetPathSet()[0].Name)
		}
		taskList = append(taskList, taskSt{
			Name:           string(taskItem.GetName()),
			PathName:       pathName,
			StartTime:      startHour + ":" + startMin,
			EndTime:        endHour + ":" + endMin,
			RunCount:       int(taskItem.GetRunCount()),
			TaskStatus:     int(taskItem.GetState()),
			TaskStatusName: define.TaskState[int(taskItem.GetState())],
		})
	}

	return taskList, nil
}

// SyncMapInfoLogic 同步地图信息逻辑
// 上位机会在地图更新变动时，同步信息到服务器
// 返回更新或新增的条数
func SyncMapInfoLogic(records []models.DeviceMap, mapPngData []byte, mapExtData []byte) ([]string, error) {
	var ids []string
	// 判定告警记录条数
	if len(records) <= 0 {
		return []string{}, errorx.New("记录不能为空", -1)
	}

	db := mysql.NewDB()
	// 判断记录是否已经存在
	for _, record := range records {
		var (
			count     int64
			oldRecord models.DeviceMap
		)
		tx := db.Model(&models.DeviceMap{}).
			Where("robot_id = ?", record.RobotID).
			Where("map_name = ?", record.MapName).
			Where("deleted_at = ?", 0).
			Session(&gorm.Session{})

		rowsAffected := tx.Take(&oldRecord).RowsAffected
		mapURL := "/" + path.Join("file", "device-admin", "device-map", record.RobotID, record.MapMd5+".png")
		mapExtURL := "/" + path.Join("file", "device-admin", "device-map", record.RobotID, record.MapExMd5+".ext")
		// 存在记录，则更新记录
		if rowsAffected > 0 {
			tx.Updates(&record)
			if oldRecord.MapMd5 != record.MapMd5 || !file.FileExists(mapURL) {
				// 保存png图片
				file.CreateMapFile(config.Config.FileSaveDir, record.RobotID, record.MapMd5, ".png", mapPngData)
				ids = append(ids, oldRecord.ID)
			}
			if oldRecord.MapExMd5 != record.MapExMd5 || !file.FileExists(mapExtURL) {
				// 保存地图扩展数据
				file.CreateMapFile(config.Config.FileSaveDir, record.RobotID, record.MapExMd5, ".ext", mapExtData)
				ids = append(ids, oldRecord.ID)
			}
		} else {
			count = db.Model(&models.DeviceMap{}).Create(&record).RowsAffected
			if count > 0 {
				// 保存png图片
				file.CreateMapFile(config.Config.FileSaveDir, record.RobotID, record.MapMd5, ".png", mapPngData)
				// 保存地图扩展数据
				file.CreateMapFile(config.Config.FileSaveDir, record.RobotID, record.MapExMd5, ".ext", mapExtData)
				ids = append(ids, record.ID)
			}
		}
	}
	return ids, nil
}
